//
//  IM_NewMessageCoder.m
//  BleTestDemo
//
//  Created by cjg on 2019/8/22.
//  Copyright © 2019 cjg. All rights reserved.
//

#import "IM_NewMessageCoder.h"

#define Tranverse16(X)  ((((UInt16)(X) & 0xff00) >> 8) |(((UInt16)(X) & 0x00ff) << 8))
#define Tranverse32(X)  ((((UInt32)(X) & 0xff000000) >> 24) | (((UInt32)(X) & 0x00ff0000) >> 8) | (((UInt32)(X) & 0x0000ff00) << 8) | (((UInt32)(X) & 0x000000ff) << 24))
#define Tranverse64(X)  ((((UInt64)(X) & 0xff00000000000000) >> 56) | (((UInt64)(X) & 0x00ff000000000000) >> 40) | (((UInt64)(X) & 0x0000ff0000000000) >> 24) | (((UInt64)(X) & 0x000000ff00000000) >> 8) | (((UInt64)(X) & 0x00000000ff000000) << 8) | (((UInt64)(X) & 0x0000000000ff0000) << 24) | (((UInt64)(X) & 0x000000000000ff00) << 40) | (((UInt64)(X) & 0x00000000000000ff) << 56))

// 静态密码表
static const uint8_t ENCRYPTION_TABLE_STATIC[256] = {
    0xED,0xB9,0xF2,0x58,0x8B,0xE3,0xC5,0xEC,0x14,0xC0,0x9D,0x42,0x60,0x17,0x0F,0x9E, 0x0B,0x98,0xDC,0x16,0x9D,0xDF,0x66,0xD1,0xC3,0x9C,0xC7,0xBF,0x4D,0xFD,0xBD,0xCE, 0xEB,0x95,0xE6,0x96,0x25,0x4F,0xA8,0x8D,0x52,0x49,0x96,0xD0,0xC2,0x80,0xBB,0xCC, 0x90,0x02,0x09,0x3E,0x1E,0x7B,0x39,0xF3,0x47,0x4A,0x20,0x00,0x6F,0x9B,0x2F,0xA9, 0x1A,0x50,0xA2,0x0E,0x06,0x21,0x9C,0xFB,0x1E,0x59,0x76,0x4A,0x83,0xD3,0xCA,0x4D, 0xDC,0xFB,0x31,0xC2,0xA6,0xDE,0x14,0x11,0x60,0x99,0x3E,0xC6,0x7A,0x41,0xC5,0x5B, 0xF6,0xCB,0xD9,0x4D,0x4F,0x62,0x2B,0x15,0x3D,0xAF,0x4D,0xCB,0x7A,0x6D,0x32,0x40, 0xAD,0x38,0xE7,0x7A,0x3B,0x1D,0x25,0x19,0x3D,0x3E,0xF4,0xE1,0xD5,0x32,0x8E,0xF2, 0xF1,0x40,0xA4,0x4E,0xD9,0x83,0xDC,0x90,0x44,0x64,0x6C,0xEB,0x02,0xCC,0xA6,0x6E, 0x6E,0x2B,0x6F,0x8B,0x67,0x09,0x3B,0xD2,0x4E,0x8C,0x3F,0x95,0x99,0x9C,0xC5,0x66, 0x67,0x7B,0xA5,0xD7,0xBA,0x89,0xE9,0x72,0x4D,0xA1,0xD6,0x57,0xF6,0x35,0x54,0x9D, 0x2D,0xE0,0x5B,0x6A,0x68,0x66,0x05,0xA8,0x0F,0x07,0xEB,0xEE,0x56,0x31,0x77,0x94, 0x05,0xF8,0x07,0xED,0xE7,0x87,0x98,0x3F,0x3E,0xB2,0xB1,0x31,0xFA,0x2D,0x94,0x7D, 0x99,0xC6,0x1F,0x83,0x66,0xD9,0x11,0x32,0x15,0x8B,0xF8,0x04,0x61,0x8E,0x04,0x81, 0xF0,0x92,0x80,0xD9,0x7E,0xB7,0xD4,0x24,0xD1,0xA4,0xAD,0x21,0x89,0x81,0x55,0x8D, 0x50,0x56,0x6A,0x28,0xD8,0xD5,0x82,0x89,0x5A,0x1C,0xEA,0x42,0x2A,0x08,0x6A,0xDF,
};

// CRC16
static const uint16_t CRC16_MODBUS_TABLE[256] = {
    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};

// CRC32
static const uint32_t CRC32_TABLE[256] = {
    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};

@interface IM_NewMessageCoder ()

@property (nonatomic , assign) uint8_t packLength;  // 数据的长度
@property (nonatomic , assign) uint32_t checkValue;
@property (nonatomic , assign) IM_NewMessageBody messagenewBody;

@end

@implementation IM_NewMessageCoder

#pragma mark -- 数据转消息
// 将收到的蓝牙数据转换成消息格式 -- 去除帧头->反转义处理->解密处理->核对并去除校验->原始数据(Format+Key+Tab+Length+Data)
- (IMTCANMessage *)transformMessageFromData:(NSData *)data {
    
    NSLog(@"需要处理的包数据 ================ %@",data);
    // 获取转义后帧主题数据
    NSData *escapeData = [self getFrameDataWithData:data];
    // 帧主题的长度
    NSUInteger escapeLength = escapeData.length;
    
    // 处理第一包数据 - 获取newBody
    if (self.packLength == 0) {
        
        IM_NewMessageBody messagenewBody;
        int newBodyOffset = 0;
        self.tabLength = 0;
        // format
        IM_NewMessageFormat format;
        uint8_t formatValue ;
        [escapeData getBytes:&formatValue range:NSMakeRange(newBodyOffset++, 1)];
        format.formatType = (formatValue & 0x80) >> 7;
        format.isHasTab = (formatValue & 0x40) >> 6;
        format.checkType = (formatValue & 0x30) >> 4;
        format.isEncrypt = (formatValue & 0x08) >> 3;
        format.dataType = (formatValue & 0x07) >> 0;
        messagenewBody.format = format;
        
        // key
        if (format.isEncrypt) {
            Byte byte ;
            [escapeData getBytes:&byte range:NSMakeRange(newBodyOffset++, 1)];
            self.keyLength ++;
            messagenewBody.key = byte;
        }
        
        // 要解密的数据
        int codeLength = (int)(escapeLength - newBodyOffset);
        NSData *beforeCodeData = [escapeData subdataWithRange:NSMakeRange(escapeLength - codeLength, codeLength)];
        
        // 解密后的数据
        NSData * hasCodeData;
        // 是否需要解密
        if (format.isEncrypt) {
            hasCodeData = [self coderOrUncoderWithData:beforeCodeData withKey:messagenewBody.key];
        }else {
            hasCodeData = beforeCodeData;
        }
        
        int dataOffset = 0;
        
        // tab
        if (format.isHasTab) {
            Byte tab[4] = {0};
            for (int i = 0; i< 4; i++) {
                Byte *byte = (Byte *)malloc(1);
                [hasCodeData getBytes:byte range:NSMakeRange(dataOffset, 1)];
                if (((byte[0] & 0x80) >> 7) == 1) {
                    tab[i] = byte[0];
                    self.tabLength ++;
                    dataOffset ++;
                }else {
                    tab[i] = byte[0];
                    self.tabLength ++;
                    dataOffset ++;
                    i = 4;
                    break;
                }
                free(byte);
            }
            uint32_t value = 0;
            for (int i = 0; i < dataOffset; i++) {
                value = value | ((tab[i] & 0x7f) << 7 *(dataOffset-i-1));
            }
            messagenewBody.tab = value;
        }
        
        // length
        uint8_t lengthValue ;
        [hasCodeData getBytes:&lengthValue range:NSMakeRange(dataOffset++, 1)];
        messagenewBody.length = lengthValue;
        
        // 获取校验位的长度
        if (format.checkType == 0) {
            self.checkLength = 0;
        }else if (format.checkType == 1) {
            self.checkLength = 1;
        }else if (format.checkType == 2) {
            self.checkLength = 2;
        }else if (format.checkType == 3) {
            self.checkLength = 4;
        }
        
        // 消息体 format、key，tab，length
        self.messagenewBody = messagenewBody;
        
        // 数据长度
        self.packLength = messagenewBody.length;
        NSLog(@"数据长度 ===============     %x",lengthValue);
        // 完整包 第一包
        if (codeLength - dataOffset == self.packLength + self.checkLength) {
            // 校验
            NSData *keydata = [hasCodeData subdataWithRange:NSMakeRange(0, codeLength)];
            NSMutableData *checkData = [NSMutableData dataWithData:[escapeData subdataWithRange:NSMakeRange(0, newBodyOffset)]];
            [checkData appendData:keydata];
            BOOL checkResult = [self checkDataWithType:format.checkType checkData:checkData];
            if (checkResult) { // 校验成功
                NSData *data = [hasCodeData subdataWithRange:NSMakeRange(dataOffset, self.packLength)];
                self.packLength = 0;
                self.keyLength = 0;
                self.tabLength = 0;
                self.checkLength = 0;
                self.packData = nil;
                
                IMTCANMessage *message = [self analysisDataFromData:data fromType:self.messagenewBody.format.dataType];
                return message;
            }else { // 校验失败
                return nil;
            }
        }else {
            self.packData = escapeData;
            return nil;
        }
        
    }else {   // 非完整包 -- 怎么凑成完整包 -- 完整版凑成后怎么处理 <aaaa2800 fd3d7358 8be3c5ec 14c09d42 60170f9e 0bfa98>
        
        // 拼接后的数据
        NSMutableData *packData = [NSMutableData dataWithData:self.packData];
        [packData appendData:escapeData];
        NSLog(@"😅 ---------------拼接后的数据---------------- %@",packData);
        NSLog(@"%hhx ======= %lx ======= %lx ======= %lx ======= %lx",self.packLength,(unsigned long)packData.length,(unsigned long)self.checkLength,(unsigned long)self.keyLength,(unsigned long)self.tabLength);
        
        if (packData.length >= self.packLength + self.checkLength + 2 + self.keyLength + self.tabLength) { // 组成完整包
            
            // key 后的数据
            NSData * hasCodeData;
            // 解密数据的长度 key之后的全部数据
            int beforeCodeLength = (int)(self.packLength + self.checkLength + 1 + self.tabLength); //19
            // 要解密的数据
            NSData *beforeCodeData = [packData subdataWithRange:NSMakeRange(self.keyLength + 1, beforeCodeLength)];
            
            // 是否需要解密
            if (self.messagenewBody.format.isEncrypt) {
                // 解密后的数据
                hasCodeData = [self coderOrUncoderWithData:beforeCodeData withKey:self.messagenewBody.key];
            }else {
                hasCodeData = beforeCodeData;
            }
            
            // 校验
            NSData *keydata = [hasCodeData subdataWithRange:NSMakeRange(0, beforeCodeLength)];
            NSMutableData *checkData = [NSMutableData dataWithData:[packData subdataWithRange:NSMakeRange(0, self.keyLength + 1)]];
            [checkData appendData:keydata];
            
            BOOL checkResult = [self checkDataWithType:self.messagenewBody.format.checkType checkData:checkData];
            
            if (checkResult) { // 校验成功
                NSData *data = [hasCodeData subdataWithRange:NSMakeRange(self.tabLength + 1, self.packLength)];
                self.packLength = 0;
                self.keyLength = 0;
                self.tabLength = 0;
                self.checkLength = 0;
                self.packData = nil;
                IMTCANMessage *message = [self analysisDataFromData:data fromType:self.messagenewBody.format.dataType];
                NSLog(@"🌹数据转消息结果 ======================== checkType:%x -- dataType:%x -- isHasTab:%x -- isEncrypt:%x -- length:%x -- tab:%x -- key:%x -- source:%x -- target:%x -- channel:%x -- property:%x -- para:%@  -- key:%@",message.newBody.format.checkType,message.newBody.format.dataType,message.newBody.format.isHasTab,message.newBody.format.isEncrypt,message.newBody.length,message.newBody.tab,message.newBody.key,message.StandardData.source,message.StandardData.target,message.StandardData.channel,message.StandardData.property,message.para,message.key);
                
                return message;
            }else { // 校验失败
                self.packData = nil;
                return nil;
            }
        }else {
            self.packData = packData;
            return nil;
        }
    }
    
    return nil;
}

#pragma mark -- 消息转数据
// 将消息对象转换成要发送的蓝牙数据 -原始数据(Format+Key+Tab+Length+Data)->计算并添加校验->加密处理->转义处理->添加帧头
- (NSData *)transformDataFromMessage:(IMTCANMessage *)message {
    
    NSMutableData *messageData = [[NSMutableData alloc] init];
    
    // format
    IM_NewMessageFormat format = message.newBody.format;
    Byte formatValue = 0x00;
    
    if (format.formatType == 1) {
        formatValue = formatValue | 0x80;
    }
    if (format.isHasTab == 1) {
        formatValue = formatValue | 0x40;
    }
    if (format.checkType) {
        formatValue = formatValue | (format.checkType << 4);
    }
    if (format.isEncrypt == 1) {
        formatValue = formatValue | 0x08;
    }
    
    formatValue = formatValue | format.dataType;
    
    // format数据
    NSData *formatData = [self byteFromUInt8:formatValue];
    [messageData appendData:formatData];
    
    // key 随机密码索引
    if (format.isEncrypt) {
        uint8_t key = message.newBody.key;
        NSData *keyData = [self byteFromUInt8:key];
        [messageData appendData:keyData];
    }
    
    // tab
    if (format.isHasTab == 1) {
        uint32_t tabValue = message.newBody.tab;
        Byte tab[4] = {0};
        NSUInteger tabLength = 0;
        
        if(tabValue < 0x80){//7位以内
            tabLength = 1;
            tab[0] = (uint8_t)tabValue;
        }else if(tabValue < 0x4000){//14位以内
            tabLength = 2;
            tab[0] = (uint8_t)((tabValue>>7)|0x80);
            tab[1] = (uint8_t)((tabValue)&0x7F);
        } else if(tabValue < 0x200000){//21位以内
            tabLength = 3;
            tab[0] = (uint8_t)((tabValue>>14)|0x80);
            tab[1] = (uint8_t)((tabValue>>7 )|0x80);
            tab[2] = (uint8_t)((tabValue)&0x7F);
        } else{ // if(tab < 0x10000000)//28位以内
            tabLength = 4;
            tab[0] = (uint8_t)((tabValue>>21)|0x80);
            tab[1] = (uint8_t)((tabValue>>14)|0x80);
            tab[2] = (uint8_t)((tabValue>>7 )|0x80);
            tab[3] = (uint8_t)((tabValue)&0x7F);
        }
        NSData*tabData = [NSData dataWithBytes:tab length:tabLength];
        [messageData appendData:tabData];
    }
    
    // length
    uint8_t packLength = message.newBody.length;
    NSData *lengthData = [self byteFromUInt8:packLength];
    [messageData appendData:lengthData];
    
    // data -- 三种格式
    if ((format.dataType == 1) | (format.dataType == 2) | (format.dataType == 3)) {
        if (format.dataType == 1) {
            uint8_t channel = message.StandardData.channel;
            NSData *channelData = [self byteFromUInt8:channel];
            [messageData appendData:channelData];
            
            uint8_t property = message.StandardData.property;
            NSData *propertyData = [self byteFromUInt8:property];
            [messageData appendData:propertyData];
            
            NSData *para = message.para;
            [messageData appendData:para];
        }
        
        if (format.dataType == 2) {
            uint8_t target = message.StandardData.target;
            NSData *targetData = [self byteFromUInt8:target];
            [messageData appendData:targetData];
            
            uint8_t channel = message.StandardData.channel;
            NSData *channelData = [self byteFromUInt8:channel];
            [messageData appendData:channelData];
            
            uint8_t property = message.StandardData.property;
            NSData *propertyData = [self byteFromUInt8:property];
            [messageData appendData:propertyData];
            
            NSData *para = message.para;
            [messageData appendData:para];
        }
        
        if (format.dataType == 3) {
            uint8_t source = message.StandardData.source;
            NSData *sourceData = [self byteFromUInt8:source];
            [messageData appendData:sourceData];
            
            uint8_t target = message.StandardData.target;
            NSData *targetData = [self byteFromUInt8:target];
            [messageData appendData:targetData];
            
            uint8_t channel = message.StandardData.channel;
            NSData *channelData = [self byteFromUInt8:channel];
            [messageData appendData:channelData];
            
            uint8_t property = message.StandardData.property;
            NSData *propertyData = [self byteFromUInt8:property];
            [messageData appendData:propertyData];
            
            NSData *para = message.para;
            [messageData appendData:para];
        }
        
    } else if ((format.dataType == 4) | (format.dataType == 5) | (format.dataType == 6)) {
        if (format.dataType == 4) {
            // cmd 转化为 data
            uint32_t cmd = message.DedicatedData.cmd;
            NSData *cmdData = [self cmdToDataWithCmd:cmd];
            [messageData appendData:cmdData];
            NSData *para = message.para;
            [messageData appendData:para];
        }
        if (format.dataType == 5) {
            uint8_t target = message.DedicatedData.target;
            NSData *targetData = [self byteFromUInt8:target];
            [messageData appendData:targetData];
            uint32_t cmd = message.DedicatedData.cmd;
            // cmd 转化为 data
            NSData *cmdData = [self cmdToDataWithCmd:cmd];
            [messageData appendData:cmdData];
            NSData *para = message.para;
            [messageData appendData:para];
        }
        if (format.dataType == 6) {
            uint8_t source = message.DedicatedData.source;
            NSData *sourceData = [self byteFromUInt8:source];
            [messageData appendData:sourceData];
            uint8_t target = message.DedicatedData.target;
            NSData *targetData = [self byteFromUInt8:target];
            [messageData appendData:targetData];
            // cmd 转化为 data
            uint32_t cmd = message.DedicatedData.cmd;
            NSData *cmdData = [self cmdToDataWithCmd:cmd];
            [messageData appendData:cmdData];
            NSData *para = message.para;
            [messageData appendData:para];
        }
    } else if (format.dataType == 6) {
        NSData *para = message.para;
        [messageData appendData:para];
    }
    
    // 获取校验位的长度
    NSUInteger checkLength = 0;
    if (format.checkType == 0) {
        checkLength = 0;
    }else if (format.checkType == 1) { // 奇偶校验
        checkLength = 1;
    }else if (format.checkType == 2) { // crc16
        checkLength = 2;
    }else if (format.checkType == 4) { // crc32
        checkLength = 4;
    }
    
    // 计算并添加校验
    NSData *allData;
    
    if (format.checkType == 0) {
    }else if (format.checkType == 1) { // 奇偶校验
        //添加奇偶校验
        messageData = [NSMutableData dataWithData:[self addParityCheckDataWithData:messageData]];
    }else if (format.checkType == 2) { // crc16
        
        uint16_t check = [self returnCrc16CheckWithData:messageData];
        NSData *checkData = [self byteFromUInt16:check];
        [messageData appendData:checkData];
    }else if (format.checkType == 3) { // crc32
        uint32_t check = [self returnCrc32CheckWithData:messageData];
        NSData *checkData = [self bytesFromUInt32:check];
        NSLog(@"crc32的校验结果 ================ %@",checkData);
        [messageData appendData:checkData];
    }
    if (format.isEncrypt) {
        NSData *coderData = [self coderOrUncoderWithData:[messageData subdataWithRange:NSMakeRange(2, messageData.length - 2)] withKey:message.newBody.key]; // 加密 key之后的全部数据
        NSData *nocodeData = [messageData subdataWithRange:NSMakeRange(0, 2)];
        NSMutableData *temp = [[NSMutableData alloc] init];
        [temp appendData:nocodeData];
        [temp appendData:coderData];
        allData = temp;
    }else {
        allData = messageData;
    }
    return [self transferredStrWithData:allData]; // 转义和添加包头
}

// 添加转义和帧头
- (NSData *)transferredStrWithData:(NSData *)data {
    
    NSUInteger length = data.length;
    Byte *bytes = (Byte *)malloc(length);
    [data getBytes:bytes length:length];
    
    Byte *finalBytes = (Byte *)malloc(length * 2);
    NSUInteger offset = 0;
    // 添加帧头
    finalBytes[offset++] = NEWFORMHEADER;
    finalBytes[offset++] = NEWFORMHEADER;
    
    // 添加标准消息体
    for (int i = 0; i < length; i++) {
        if (bytes[i] == NEWFORMHEADER || bytes[i] == NEWESCAPECHARACTER) {
            finalBytes[offset++] = NEWESCAPECHARACTER;
        }
        finalBytes[offset++] = bytes[i];
    }
    free(bytes);
    
    NSData *resultData = [NSData dataWithBytes:finalBytes length:offset];
    free(finalBytes);
    
    return resultData;
}

// 获取帧主题 -- 去除包头、反转义--
- (NSData *)getFrameDataWithData:(NSData *)data {
    // 收到的数据
    NSUInteger length = [data length];
    Byte *bytes = (Byte *) malloc(length);
    [data getBytes:bytes length:length];
    
    // 帧主体数据 -- 去包头反转义后的数据
    Byte *unpackedBytes = (Byte *) malloc(length);
    int offset = 0;
    BOOL lookForNextData = NO;
    // 去包头、 反转义
    for (int i = 0; i < length; i++) {
        if ((bytes[0] == 0xaa) & (bytes[1] == 0xaa) & (i == 0)) { // 说明是第一包
            i = 2;
            self.packData = nil;
            self.packLength = 0;
            NSLog(@"=============第一个包带包头🙆‍♂️🙆");
        }
        Byte byte = bytes[i];
        if (lookForNextData) {
            unpackedBytes[offset++] = byte;
            lookForNextData = NO;
        } else {
            if (byte == NEWESCAPECHARACTER) {
                lookForNextData = YES;
                continue;
            } else {
                lookForNextData = NO;
            }
            unpackedBytes[offset++] = byte;
        }
    }
    free(bytes);
    
    // 转义后帧主题数据 实际长度是offset
    NSData *escapeData = [NSData dataWithBytes:unpackedBytes length:offset];
    free(unpackedBytes);
    return escapeData;
}

// 解析数据格式
- (IMTCANMessage *)analysisDataFromData:(NSData *)data fromType:(int)fromType{
    if ((fromType == 1) | (fromType == 2) | (fromType == 3)) {
        return [self analysisStandardDataFromData:data fromType:fromType];
    }
    if ((fromType == 4) | (fromType == 5) | (fromType == 6)) {
        return [self analysisDedicatedDataFromData:data fromType:fromType];
    }
    if (fromType == 0) {
        return [self analysisFreedomDataFromData:data fromType:fromType];
    }
    return nil;
}

// 解析标准组格式
- (IMTCANMessage *)analysisStandardDataFromData:(NSData *)data fromType:(int)fromType{
    
    if (fromType == 1){ // channel + property + para
        IM_NewStandardDataFormat standardDataFormat;
        uint8_t channel ;
        [data getBytes:&channel range:NSMakeRange(0, 1)];
        standardDataFormat.channel = channel;
        uint8_t property ;
        [data getBytes:&property range:NSMakeRange(1, 1)];
        standardDataFormat.property = property;
        NSData *para = [data subdataWithRange:NSMakeRange(2, data.length - 2)];
        IMTCANMessage *message = [[IMTCANMessage alloc] initWithBody:self.messagenewBody StandardData:(standardDataFormat) data:para];
        return message;
    }else if (fromType == 2) { // target + channel + property + para
        IM_NewStandardDataFormat standardDataFormat;
        uint8_t target ;
        [data getBytes:&target range:NSMakeRange(0, 1)];
        standardDataFormat.target = target;
        uint8_t channel ;
        [data getBytes:&channel range:NSMakeRange(1, 1)];
        standardDataFormat.channel = channel;
        uint8_t property ;
        [data getBytes:&property range:NSMakeRange(2, 1)];
        standardDataFormat.property = property;
        NSData *para = [data subdataWithRange:NSMakeRange(3, data.length - 3)];
        IMTCANMessage *message = [[IMTCANMessage alloc] initWithBody:self.messagenewBody StandardData:(standardDataFormat) data:para];
        return message;
    }else if (fromType == 3) { // source + target + channel + property + para
        IM_NewStandardDataFormat standardDataFormat;
        uint8_t source ;
        [data getBytes:&source range:NSMakeRange(0, 1)];
        standardDataFormat.source = source;
        uint8_t target ;
        [data getBytes:&target range:NSMakeRange(1, 1)];
        standardDataFormat.target = target;
        uint8_t channel ;
        [data getBytes:&channel range:NSMakeRange(2, 1)];
        standardDataFormat.channel = channel;
        uint8_t property ;
        [data getBytes:&property range:NSMakeRange(3, 1)];
        standardDataFormat.property = property;
        NSData *para = [data subdataWithRange:NSMakeRange(4, data.length - 4)];
        IMTCANMessage *message = [[IMTCANMessage alloc] initWithBody:self.messagenewBody StandardData:(standardDataFormat) data:para];
        return message;
    }
    
    return nil;
}

// 解析专用组格式
- (IMTCANMessage *)analysisDedicatedDataFromData:(NSData *)data fromType:(int)fromType{
    
    NSUInteger length = [data length];
    Byte *bytes = (Byte *) malloc(length);
    [data getBytes:bytes length:length];
    
    if (fromType == 4){ // cmd + para
        __block NSUInteger cmdOffset = 0;
        IM_NewDedicatedDataFormat dedicatedDataFormat;
        // 解析 cmd
        uint32_t cmdValue = [self getCmdWithData:data lengthBlock:^(NSUInteger offset) {
            cmdOffset = offset;
            NSLog(@"cmd的长度 ========== %lu == %lu",(unsigned long)offset,(unsigned long)cmdOffset);
        }];
        dedicatedDataFormat.cmd = cmdValue;
        NSData *para = [data subdataWithRange:NSMakeRange(cmdOffset, length - cmdOffset)];
        IMTCANMessage *message = [[IMTCANMessage alloc] initWithBody:self.messagenewBody DedicatedData:dedicatedDataFormat data:para];
        message.newBody = self.messagenewBody;
        return message;
        
    }else if (fromType == 5) { // target + cmd + para
        __block NSUInteger cmdOffset = 0;
        IM_NewDedicatedDataFormat dedicatedDataFormat;
        
        uint8_t target ;
        [data getBytes:&target range:NSMakeRange(cmdOffset++, 1)];
        dedicatedDataFormat.target = target;
        
        // 解析 cmd
        uint32_t cmdValue = [self getCmdWithData:[data subdataWithRange:NSMakeRange(cmdOffset, data.length - cmdOffset)] lengthBlock:^(NSUInteger offset) {
            cmdOffset += offset;
            NSLog(@"cmd的长度 ========== %lu == %lu",(unsigned long)offset,(unsigned long)cmdOffset);
        }];
        
        dedicatedDataFormat.cmd = cmdValue;
        NSData *para = [data subdataWithRange:NSMakeRange(cmdOffset, length - cmdOffset)];
        IMTCANMessage *message = [[IMTCANMessage alloc] initWithBody:self.messagenewBody DedicatedData:dedicatedDataFormat data:para];
        message.newBody = self.messagenewBody;
        return message;
        
    }else if (fromType == 6) { // source +  target + cmd + para
        __block NSUInteger cmdOffset = 0;
        IM_NewDedicatedDataFormat dedicatedDataFormat;
        
        uint8_t source ;
        [data getBytes:&source range:NSMakeRange(cmdOffset++, 1)];
        dedicatedDataFormat.source = source;
        
        uint8_t target ;
        [data getBytes:&target range:NSMakeRange(cmdOffset++, 1)];
        dedicatedDataFormat.target = target;
        
        // 解析 cmd
        uint32_t cmdValue = [self getCmdWithData:[data subdataWithRange:NSMakeRange(cmdOffset, data.length - cmdOffset)] lengthBlock:^(NSUInteger offset) {
            cmdOffset += offset;
            NSLog(@"cmd的长度 ========== %lu == %lu",(unsigned long)offset,(unsigned long)cmdOffset);
        }];
        
        dedicatedDataFormat.cmd = cmdValue;
        NSData *para = [data subdataWithRange:NSMakeRange(cmdOffset, length - cmdOffset)];
        IMTCANMessage *message = [[IMTCANMessage alloc] initWithBody:self.messagenewBody DedicatedData:dedicatedDataFormat data:para];
        message.newBody = self.messagenewBody;
        return message;
    }
    
    return nil;
}

// 解析自由组格式
- (IMTCANMessage *)analysisFreedomDataFromData:(NSData *)data fromType:(int)fromType{
    if (fromType == 0){ // para
        IMTCANMessage *message = [[IMTCANMessage alloc] initWithBody:self.messagenewBody data:data];
        message.newBody = self.messagenewBody;
        return message;
    }
    return nil;
}

#pragma mark -  数据加密解密
- (NSData *)coderOrUncoderWithData:(NSData *)data withKey:(uint8_t)key{
    // 获取密码表 -- 暂时使用静态密码表
    Byte codeKey[256] = {0};
    [self.CodeKey getBytes:&codeKey length:256];
    
    NSUInteger length = data.length;
    Byte *bytes = (Byte *) malloc(length);
    [data getBytes:bytes length:length];
    
    Byte *resultBytes = (Byte *) malloc(length);
    for (int i = 0; i < length; i ++) {
        Byte codeTemp = bytes[i]^ENCRYPTION_TABLE_STATIC[(i + key)%256];
        resultBytes[i] = codeTemp;
    }
    NSData *resultData = [NSData dataWithBytes:resultBytes length:length];
    free(bytes);
    free(resultBytes);
    return resultData;
}

#pragma mark -  计算校验值
// 添加CRC-16/MODBUS校验 -- 需要转化大小端
-(uint16_t)returnCrc16CheckWithData:(NSData *)data {
    NSUInteger length = data.length;
    Byte *bytes = (Byte *) malloc(length);
    [data getBytes:bytes length:length];
    uint16_t crc16 = 0xFFFF; //初值 0xFFFFFFFF
    while (length--) {
        crc16 = (crc16 >> 8) ^ CRC16_MODBUS_TABLE [(crc16 ^ *bytes++) & 0xFF];
    }
    return Tranverse16(crc16);
}

// 添加Crc32校验 -- 需要转化大小端
-(uint32_t)returnCrc32CheckWithData:(NSData *)data {
    NSUInteger length = data.length;
    Byte *bytes = (Byte *) malloc(length);
    [data getBytes:bytes length:length];
    
    uint32_t crc32 = 0xFFFFFFFF; //初值 0xFFFFFFFF
    while (length--) {
        crc32 = (crc32 >> 8) ^ CRC32_TABLE [(crc32 ^ *bytes++) & 0xFF];
    }
    crc32 = crc32 ^ 0xffffffff;
    return Tranverse32(crc32);
}

// 添加奇偶校验
- (NSData *)addParityCheckDataWithData:(NSData *)data {
    NSUInteger length = data.length;
    Byte *bytes = (Byte *) malloc(length + 1);
    [data getBytes:bytes length:length];
    
    uint8_t result = bytes[0];
    for (int i = 1; i < length ; i ++) {
        uint8_t tempByte = bytes[i];
        result = result^tempByte;
    }
    bytes[length] = result;
    NSData *resultData = [NSData dataWithBytes:bytes length:length + 1];
    free(bytes);
    
    return resultData;
}

#pragma mark -- 校验结果
- (BOOL)checkDataWithType:(int)checkType checkData:(NSData *)checkData {
    if (checkType == 0) {
        return YES;
    }else if (checkType == 1) {
        return [self parityCheckWithData:checkData];
    }else if (checkType == 2) {
        return [self crc16CheckWithData:checkData];
    }else if (checkType == 3){
        return [self crc32CheckWithData:checkData];
    }
    return NO; // 收到校验方式错误
}

// 奇偶校验 --- 默认偶校验即正确的数据帧所有字节(包括校验字节)异或为 0
- (BOOL)parityCheckWithData:(NSData *)data {
    NSUInteger length = data.length;
    Byte *bytes = (Byte *) malloc(length);
    [data getBytes:bytes length:length];
    uint8_t result = bytes[0];
    for (int i = 1; i < length; i ++) {
        uint8_t tempByte = bytes[i];
        result = result^tempByte;
    }
    free(bytes);
    return result == 0;
}

// CRC16校验 -- 结果
- (BOOL)crc16CheckWithData:(NSData *)data {
    
    NSUInteger length = data.length - 2;
    Byte *bytes = (Byte *) malloc(length);
    [data getBytes:bytes length:length];
    
    uint16_t crc16 = 0xFFFF; // 初值 0xFFFFFFFF
    while (length--) {
        crc16 = (crc16 >> 8) ^ CRC16_MODBUS_TABLE [(crc16 ^ *bytes++) & 0xFF];
    }
    uint16_t checkValue;
    [data getBytes:&checkValue range:NSMakeRange(data.length - 2, 2)];
    return crc16 == checkValue;
}

// CRC32校验 -- 结果
- (BOOL)crc32CheckWithData:(NSData *)data {
    
    NSUInteger length = data.length - 4;
    Byte *bytes = (Byte *) malloc(length);
    [data getBytes:bytes length:length];
    
    uint32_t crc32 = 0xFFFFFFFF; // 初值 0xFFFFFFFF
    while (length--) {
        crc32 = (crc32 >> 8) ^ CRC32_TABLE [(crc32 ^ *bytes++) & 0xFF];
    }
    uint32_t checkValue ;
    [data getBytes:&checkValue range:NSMakeRange(data.length - 4, 4)];
    return (crc32 ^ 0xffffffff) == checkValue;
}

#pragma mark ------- cmd解析和封装
// cmd  解析
- (uint32_t)getCmdWithData:(NSData *)data lengthBlock:(void(^)(NSUInteger offset))offset {
    
    uint32_t cmdResult;
    
    NSUInteger length = data.length;
    uint32_t head;
    uint32_t cmd;
    uint8_t temp;
    uint8_t count = 0;
    if(length == 0)
    {
        offset(0);
        return 0;
    }
    Byte *bytes = (Byte *)malloc(length);
    [data getBytes:bytes length:length];
    temp = bytes[count ++];
    head = ((uint32_t)(temp & 0xc0)) << 24; // 第一个字节最高两位，bit7,bit6 分别表示传输方向，读写属性
    cmd = temp&0x1F; // bit[4:0] 表示实际功能号
    if((temp&0x20) == 0) // bit5 表示是否扩展长度
    {
        offset(count);
        cmdResult = head|cmd;
        return cmdResult;
    }
    // 拓展格式
    while(count < length && count < 4)
    {
        cmd <<= 7;
        temp = bytes[count++];
        cmd |= (temp&0x7F);
        if((temp & 0x80) == 0)
        {
            offset(count);
            cmdResult = head|cmd;
            return cmdResult;
        }
    }
    offset(count);
    return 0;
}

// 将 cmd 转化为 data
- (NSData *)cmdToDataWithCmd:(uint32_t)cmd {
    Byte cmdBytes[4] = {0};
    int cmdLength = 0;
    uint32_t temp = cmd&0x03FFFFFF;
    uint8_t head = (cmd>>24)&0xC0;
    if(temp < 0x20) {  // 5位以内
        cmdBytes[0] = (uint8_t)(temp)|head;
        cmdLength = 1;
    } else if(temp < 0x1000){ // 12位以内
        cmdBytes[0] = (uint8_t)((temp>>7)|0x20)|head;
        cmdBytes[1] = (uint8_t)((temp)&0x7F);
        cmdLength = 2;
    } else if(temp < 0x80000) { // 19位以内
        cmdBytes[0] = (uint8_t)((temp>>14)|0x20)|head;
        cmdBytes[1] = (uint8_t)((temp>>7) |0x80);
        cmdBytes[2] = (uint8_t)((temp)&0x7F);
        cmdLength = 3;
    } else { // if(temp < 0x4000000)//26位以内
        cmdBytes[0] = (uint8_t)((temp>>21)|0x20)|head;
        cmdBytes[1] = (uint8_t)((temp>>14)|0x80);
        cmdBytes[2] = (uint8_t)((temp>>7) |0x80);
        cmdBytes[3] = (uint8_t)((temp)&0x7F);
        cmdLength = 4;
    }
    
    NSData *cmdData = [NSData dataWithBytes:cmdBytes length:cmdLength];
    return cmdData;
}

#pragma mark -- tool
- (NSData *)byteFromUInt8:(uint8_t)val
{
    NSMutableData *valData = [[NSMutableData alloc] init];
    unsigned char valChar[1];
    valChar[0] = 0xff & val;
    [valData appendBytes:valChar length:1];
    return [self dataWithReverse:valData];
}

- (NSData *)byteFromUInt16:(uint16_t)val
{
    NSMutableData *valData = [[NSMutableData alloc] init];
    unsigned char valChar[2];
    valChar[0] = 0xff & val;
    valChar[1] = (0xff00 & val) >> 8;
    [valData appendBytes:valChar length:2];
    return [self dataWithReverse:valData];
}

- (NSData *)bytesFromUInt32:(uint32_t)val
{
    NSMutableData *valData = [[NSMutableData alloc] init];
    unsigned char valChar[4];
    valChar[0] = 0xff & val;
    valChar[1] = (0xff00 & val) >> 8;
    valChar[2] = (0xff0000 & val) >> 16;
    valChar[3] = (0xff000000 & val) >> 24;
    [valData appendBytes:valChar length:4];
    return [self dataWithReverse:valData];
}

// 大小端反转
- (NSData *)dataWithReverse:(NSData *)srcData
{
    NSUInteger byteCount = srcData.length;
    NSMutableData *dstData = [[NSMutableData alloc] initWithData:srcData];
    NSUInteger halfLength = byteCount / 2;
    for (NSUInteger i=0; i<halfLength; i++) {
        NSRange begin = NSMakeRange(i, 1);
        NSRange end = NSMakeRange(byteCount - i - 1, 1);
        NSData *beginData = [srcData subdataWithRange:begin];
        NSData *endData = [srcData subdataWithRange:end];
        [dstData replaceBytesInRange:begin withBytes:endData.bytes];
        [dstData replaceBytesInRange:end withBytes:beginData.bytes];
    }
    return dstData;
}

@end
